package com.xuelang.pipeline.artifact.app.resource.impl;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.xuelang.hiforce.base.tracing.TracingUtils;
import com.xuelang.pipeline.artifact.app.harborv2.ArtifactService;
import com.xuelang.pipeline.artifact.app.harborv2.enums.HarborWebhookEventTypeEnum;
import com.xuelang.pipeline.artifact.app.harborv2.request.SpecificArtifactQuery;
import com.xuelang.pipeline.artifact.app.harborv2.response.SpecificArtifactResponse;
import com.xuelang.pipeline.artifact.app.harborv2.xo.Reference;
import com.xuelang.pipeline.artifact.app.nexus3v1.enums.NexusWebhookEnum;
import com.xuelang.pipeline.artifact.app.nexus3v1.request.WebhookRepositoryAssetRequest;
import com.xuelang.pipeline.artifact.app.nexus3v1.request.WebhookRepositoryComponentRequest;
import com.xuelang.pipeline.artifact.app.nexus3v1.xo.ApiResponseXO;
import com.xuelang.pipeline.artifact.app.nexus3v1.xo.ComponentInfo;
import com.xuelang.pipeline.artifact.app.resource.CapabilityWebhookRepositoryService;
import com.xuelang.pipeline.artifact.app.resource.request.HarborEventRequest;
import com.xuelang.pipeline.artifact.client.common.constant.ArtifactConstant;
import com.xuelang.pipeline.artifact.client.common.constant.Constant;
import com.xuelang.pipeline.artifact.client.common.util.MavenUtil;
import com.xuelang.pipeline.artifact.domain.resource.ArtifactTool;
import com.xuelang.pipeline.artifact.domain.resource.RepositoryComponent;
import com.xuelang.pipeline.artifact.domain.resource.RepositoryPackage;
import com.xuelang.pipeline.artifact.domain.resource.service.ArtifactToolDomainService;
import com.xuelang.pipeline.artifact.domain.resource.service.RepositoryComponentDomainService;
import com.xuelang.pipeline.artifact.domain.resource.service.RepositoryPackageDomainService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Optional;

/**
 * @author xiwen.zxg
 * @since 2024/7/11
 */
@Slf4j
@Service
public class CapabilityWebhookRepositoryServiceImpl implements CapabilityWebhookRepositoryService {

    @Autowired
    RepositoryPackageDomainService repositoryPackageDomainService;
    @Autowired
    RepositoryComponentDomainService repositoryComponentDomainService;
    @Autowired
    ArtifactToolDomainService artifactToolDomainService;
    @Autowired
    ArtifactService artifactService;

    private String getInstanceRepositoryName(String repositoryName) {
        if (null == repositoryName) {
            return repositoryName;
        }
        if (!repositoryName.startsWith("hosted-")) {
            return repositoryName;
        }
        return repositoryName.replaceFirst("hosted-", "");
    }
    private String getHostedInstanceRepositoryName(String repositoryName) {
        if (null == repositoryName) {
            return repositoryName;
        }
        if (repositoryName.startsWith("hosted-")) {
            return repositoryName;
        }
        return "hosted-" + repositoryName;
    }
    private String getGroupInstanceRepositoryName(String repositoryName) {
        if (null == repositoryName) {
            return repositoryName;
        }
        if (repositoryName.startsWith("group-")) {
            return repositoryName;
        }
        return "group-" + repositoryName;
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public synchronized void rmRepositoryComponent(WebhookRepositoryComponentRequest webhookRepositoryRequest) {
        NexusWebhookEnum.EventActionEnum eventAction =  NexusWebhookEnum.EventActionEnum.getByName(webhookRepositoryRequest.getAction());
        ComponentInfo component = webhookRepositoryRequest.getComponent();
        String hostedInstanceRepositoryName = getHostedInstanceRepositoryName(webhookRepositoryRequest.getRepositoryName());
        String instanceRepositoryName = getInstanceRepositoryName(webhookRepositoryRequest.getRepositoryName());
        String initiator = webhookRepositoryRequest.getInitiator();
        if (component == null) {
            return;
        }
        String restId = component.getComponentId();
        String pushUser = (StrUtil.isNotBlank(initiator)) ? Optional.of(initiator.split(Constant.DEFAULT_URL_PATH_SEPARATOR)).map(strings -> strings[0]).orElse("") : "";
        RepositoryComponent repositoryComponent = repositoryComponentDomainService.query(restId);
        RepositoryPackage repositoryPackage = repositoryPackageDomainService.queryByPackage(instanceRepositoryName, component.getName(), component.getGroup(), component.getFormat());
        ArtifactTool artifactTool = Optional.ofNullable(artifactToolDomainService.getArtifactToolByInstanceRepositoryName(instanceRepositoryName)).orElseGet(ArtifactTool::new);
        boolean existsRepositoryComponent = (repositoryComponent != null);
        boolean existsRepositoryPackage = (repositoryPackage != null);

        switch(eventAction) {
            case CREATED:
                // 创建仓库组件
            case UPDATED:
                // 更新仓库组件
                if (existsRepositoryPackage) {
                    // 存在制品包，则更新制品包信息
                    if (existsRepositoryComponent) {
                        // 存在制品组件，则更新制品组件信息
                        repositoryComponentDomainService.update(repositoryComponent);
                    } else {
                        // 不存在制品组件，则新增制品组件信息
                        repositoryComponentDomainService.updateComponentsToOldVersion(repositoryPackage.getUuid());
                        repositoryComponentDomainService.save(newRepositoryComponent(artifactTool, component, repositoryPackage.getUuid(), pushUser, instanceRepositoryName));
                        // 更新制品包，版本数量+1
                        repositoryPackage.setComponentCount(repositoryPackage.getComponentCount() + 1);
                    }
                    // 更新制品包，最新推送版本、最近更新时间
                    repositoryPackage.setFormat(component.getFormat());
                    repositoryPackage.setNameId(component.getName());
                    repositoryPackage.setGroupId(component.getGroup());
                    repositoryPackage.setLatestVersion(component.getVersion());
                    repositoryPackage.setPackageName(MavenUtil.joinGroupAndName(repositoryPackage.getGroupId(), repositoryPackage.getNameId()));
                    repositoryPackage.setUpdaterId(TracingUtils.getUserId());
                    repositoryPackageDomainService.update(repositoryPackage);
                } else {
                    // 不存在制品包，则新增制品包信息
                    String newPackageUuid = IdUtil.fastSimpleUUID();
                    // 新增制品组件
                    repositoryComponentDomainService.save(newRepositoryComponent(artifactTool, component, newPackageUuid, pushUser, instanceRepositoryName));
                    // 新增制品包
                    repositoryPackageDomainService.save(newRepositoryPackage(artifactTool, component, newPackageUuid, instanceRepositoryName));
                }
                break;
            case DELETED:
                // 删除仓库组件
                // 先删除本制品组件
                repositoryComponentDomainService.delete(restId);
                // 更新制品包信息，最新推送版本、版本数量-1、最近更新时间
                String latestVersion = repositoryComponentDomainService.queryLatestVersion(instanceRepositoryName, component.getName(), component.getGroup(), component.getFormat());
                repositoryPackageDomainService.updateByPackage(instanceRepositoryName, component.getName(), component.getGroup(), component.getFormat(), Optional.ofNullable(latestVersion).orElse("--"));
                break;
            default:
                log.info("暂不处理的nexus-webhook事件类型：{}", eventAction);
        }

    }

    @Override
    public void rmRepositoryAsset(WebhookRepositoryAssetRequest webhookRepositoryRequest) {

    }

    @Override
    public synchronized void processHarborArtifact(HarborEventRequest payload) {
        String type = payload.getType();
        String operator = payload.getOperator();
        HarborEventRequest.ArtifactEventData eventData = payload.getEventData();
        HarborEventRequest.Repository repository = eventData.getRepository();
        List<HarborEventRequest.Resource> resources = eventData.getResources();
        if (repository == null) {
            return;
        }

        HarborWebhookEventTypeEnum webhookEventType = HarborWebhookEventTypeEnum.getByName(type);
        String instanceRepositoryName = getInstanceRepositoryName(repository.getNamespace());
        String hostedInstanceRepositoryName = getHostedInstanceRepositoryName(repository.getNamespace());
        String packageName = repository.getName();
        String currentPushVersion = Optional.ofNullable(resources).map(resourceList -> resourceList.get(0)).map(HarborEventRequest.Resource::getTag).orElse("");
        String currentDigest = Optional.ofNullable(resources).map(resourceList -> resourceList.get(0)).map(HarborEventRequest.Resource::getDigest).orElse("");
        RepositoryPackage repositoryPackage = repositoryPackageDomainService.queryByPackageName(instanceRepositoryName, packageName);
        ArtifactTool artifactTool = Optional.ofNullable(artifactToolDomainService.getArtifactToolByInstanceRepositoryName(instanceRepositoryName)).orElseGet(ArtifactTool::new);
        RepositoryComponent repositoryComponent = repositoryComponentDomainService.queryContainsDigestAndPushVersion(instanceRepositoryName, packageName, currentDigest, currentPushVersion, ArtifactConstant.HARBOR_ARTIFACT_ASSET_FORMAT);

        boolean existsRepositoryPackage = (repositoryPackage != null);
        boolean existsRepositoryComponent = (repositoryComponent != null);

        switch(webhookEventType) {
            case PUSH_ARTIFACT:
                // 推送镜像
                if (existsRepositoryPackage) {
                    // 存在制品包，则更新制品包信息
                    if (existsRepositoryComponent) {
                        // 存在制品组件，则更新制品组件信息
                        repositoryComponentDomainService.update(repositoryComponent);
                    } else {
                        // 不存在制品组件，则新增制品组件信息
                        repositoryComponentDomainService.updateComponentsToOldVersion(repositoryPackage.getUuid());
                        repositoryComponentDomainService.save(newHarborRepositoryComponent(artifactTool, operator, packageName, currentPushVersion, repositoryPackage.getUuid(), instanceRepositoryName));
                        // 更新制品包，版本数量+1
                        repositoryPackage.setComponentCount(repositoryPackage.getComponentCount() + 1);
                    }

                    // 更新制品包，最新推送版本、最近更新时间
                    repositoryPackage.setFormat(ArtifactConstant.HARBOR_ARTIFACT_ASSET_FORMAT);
                    repositoryPackage.setLatestVersion(currentPushVersion);
                    repositoryPackage.setPackageName(packageName);
                    repositoryPackage.setUpdaterId(TracingUtils.getUserId());
                    repositoryPackageDomainService.update(repositoryPackage);
                } else {
                    // 不存在制品包，则新增制品包信息
                    // 新增制品包
                    String newPackageUuid = IdUtil.fastSimpleUUID();
                    repositoryPackageDomainService.save(newHarborRepositoryPackage(artifactTool, packageName, currentPushVersion ,newPackageUuid, instanceRepositoryName));
                    // 新增制品组件
                    repositoryComponentDomainService.save(newHarborRepositoryComponent(artifactTool, operator, packageName, currentPushVersion, newPackageUuid, instanceRepositoryName));
                }

                break;
            case DELETE_ARTIFACT:
                // 删除镜像
                if (repositoryComponent != null) {
                    String restId = repositoryComponent.getRestId();
                    // 先删除本制品组件
                    repositoryComponentDomainService.delete(restId);
                    // 更新制品包信息，最新推送版本、版本数量-1、最近更新时间
                    String latestVersion = repositoryComponentDomainService.queryLatestVersionByPackageName(instanceRepositoryName, packageName, ArtifactConstant.HARBOR_ARTIFACT_ASSET_FORMAT);
                    repositoryPackageDomainService.updateByPackageName(instanceRepositoryName, packageName, Optional.ofNullable(latestVersion).orElse("--"), ArtifactConstant.HARBOR_ARTIFACT_ASSET_FORMAT);

                }
                break;
            default:
                log.info("暂不处理的harbor-webhook事件类型: {}", type);
        }
    }


    /**
     * 新增制品组件-Harbor
     *
     * @param artifactTool
     * @param pushUser
     * @param packageName
     * @param currentPushVersion
     * @param repositoryPackageUuid
     * @param repositoryName
     * @return
     */
    private RepositoryComponent newHarborRepositoryComponent(ArtifactTool artifactTool, String pushUser, String packageName, String currentPushVersion, String repositoryPackageUuid, String repositoryName) {
        ApiResponseXO<SpecificArtifactResponse> specificArtifactResponse = artifactService.getRepositorySpecificArtifact(repositoryName, packageName, currentPushVersion, SpecificArtifactQuery.builder().build());
        if (specificArtifactResponse.isSuccess() && specificArtifactResponse.getData() != null) {
            SpecificArtifactResponse data = specificArtifactResponse.getData();
            String dirDigest = data.getDigest();
            // references中获取annotations不为空的Reference对象
            Reference reference = data.getReferences().stream().filter(ref -> ref.getAnnotations() != null).findFirst().orElse(null);
            if (reference != null) {
                String metaDigest = reference.getChildDigest();
                String mainDigest = reference.getAnnotations().get("vnd.docker.reference.digest");
                //为主Artifact的sha256[=versionNo]
                String restId = mainDigest + Constant.DEFAULT_MIDDLE_SEPARATOR + packageName + Constant.DEFAULT_MIDDLE_SEPARATOR + currentPushVersion;
                //为主、次、辅Artifact的sha256+tags.name[=versionNo]，第二次进来判断包含该digest或者该版本则跳过；
                String scriptId = dirDigest + metaDigest + restId;

                RepositoryComponent newRepositoryComponent = new RepositoryComponent();
                newRepositoryComponent.setPackageUuid(repositoryPackageUuid);
                newRepositoryComponent.setArtifactUuid(artifactTool.getUuid());
                newRepositoryComponent.setInstanceRepositoryName(artifactTool.getInstanceRepositoryName());
                newRepositoryComponent.setScriptId(scriptId);
                newRepositoryComponent.setRestId(restId);
                newRepositoryComponent.setFormat(ArtifactConstant.HARBOR_ARTIFACT_ASSET_FORMAT);
                newRepositoryComponent.setPackageName(packageName);
                newRepositoryComponent.setVersion(currentPushVersion);
                newRepositoryComponent.setIsLatest(true);
                newRepositoryComponent.setPushUser(pushUser);
                newRepositoryComponent.setPomXml("<xml></xml>");
                newRepositoryComponent.setCreatorId(TracingUtils.getUserId());
                newRepositoryComponent.setUpdaterId(TracingUtils.getUserId());
                return newRepositoryComponent;
            }
        }
        return null;
    }

    /**
     * 新增制品包-Harbor
     *
     * @param artifactTool
     * @param packageName
     * @param currentPushVersion
     * @param repositoryPackageUuid
     * @param repositoryName
     * @return
     */
    private RepositoryPackage newHarborRepositoryPackage(ArtifactTool artifactTool, String packageName, String currentPushVersion, String repositoryPackageUuid, String repositoryName) {
        RepositoryPackage newRepositoryPackage = new RepositoryPackage();
        newRepositoryPackage.setUuid(repositoryPackageUuid);
        newRepositoryPackage.setInstanceRepositoryName(repositoryName);
        newRepositoryPackage.setArtifactUuid(artifactTool.getUuid());
        newRepositoryPackage.setArtifactType(artifactTool.getArtifactType());
        newRepositoryPackage.setFormat(ArtifactConstant.HARBOR_ARTIFACT_ASSET_FORMAT);
        newRepositoryPackage.setLatestVersion(currentPushVersion);
        newRepositoryPackage.setComponentCount(ArtifactConstant.COMPONENT_INIT_VALUE);
        newRepositoryPackage.setPackageName(packageName);
        newRepositoryPackage.setCreatorId(TracingUtils.getUserId());
        newRepositoryPackage.setUpdaterId(TracingUtils.getUserId());
        return newRepositoryPackage;
    }


    /**
     * 新增制品包
     *
     * @param artifactTool
     * @param component
     * @param repositoryPackageUuid
     * @param repositoryName
     * @return
     */
    private RepositoryPackage newRepositoryPackage(ArtifactTool artifactTool, ComponentInfo component, String repositoryPackageUuid, String repositoryName) {
        RepositoryPackage newRepositoryPackage = new RepositoryPackage();
        newRepositoryPackage.setUuid(repositoryPackageUuid);
        newRepositoryPackage.setInstanceRepositoryName(repositoryName);
        newRepositoryPackage.setArtifactUuid(artifactTool.getUuid());
        newRepositoryPackage.setArtifactType(artifactTool.getArtifactType());
        newRepositoryPackage.setFormat(component.getFormat());
        newRepositoryPackage.setNameId(component.getName());
        newRepositoryPackage.setGroupId(component.getGroup());
        newRepositoryPackage.setLatestVersion(component.getVersion());
        newRepositoryPackage.setComponentCount(ArtifactConstant.COMPONENT_INIT_VALUE);
        newRepositoryPackage.setPackageName(MavenUtil.joinGroupAndName(newRepositoryPackage.getGroupId(), newRepositoryPackage.getNameId()));
        newRepositoryPackage.setCreatorId(TracingUtils.getUserId());
        newRepositoryPackage.setUpdaterId(TracingUtils.getUserId());
        return newRepositoryPackage;
    }

    /**
     * 新增制品组件
     *
     * @param artifactTool
     * @param component
     * @param repositoryPackageUuid
     * @param pushUser
     * @return
     */
    private RepositoryComponent newRepositoryComponent(ArtifactTool artifactTool, ComponentInfo component, String repositoryPackageUuid, String pushUser, String instanceRepositoryName) {
        RepositoryComponent newRepositoryComponent = new RepositoryComponent();
        newRepositoryComponent.setPackageUuid(repositoryPackageUuid);
        newRepositoryComponent.setArtifactUuid(artifactTool.getUuid());
        newRepositoryComponent.setInstanceRepositoryName(instanceRepositoryName);
        newRepositoryComponent.setScriptId(component.getId());
        newRepositoryComponent.setRestId(component.getComponentId());
        newRepositoryComponent.setFormat(component.getFormat());
        newRepositoryComponent.setNameId(component.getName());
        newRepositoryComponent.setGroupId(component.getGroup());
        newRepositoryComponent.setPackageName(MavenUtil.joinGroupAndName(newRepositoryComponent.getGroupId(), newRepositoryComponent.getNameId()));
        newRepositoryComponent.setVersion(component.getVersion());
        newRepositoryComponent.setIsLatest(true);
        newRepositoryComponent.setPushUser(pushUser);
        newRepositoryComponent.setPomXml("<xml></xml>");
        newRepositoryComponent.setCreatorId(TracingUtils.getUserId());
        newRepositoryComponent.setUpdaterId(TracingUtils.getUserId());
        return newRepositoryComponent;
    }


}
